<template>
  <div class="thumbnail-grid-container" ref="containerRef">
    <!-- 虚拟列表容器 -->
    <div 
      class="virtual-list" 
      :style="{ height: containerHeight + 'px' }"
      @scroll="handleScroll"
    >
      <!-- 占位符高度 -->
      <div :style="{ height: topSpacerHeight + 'px' }"></div>
      
      <!-- 可见项目 -->
      <div 
        v-for="(group, index) in visibleGroups" 
        :key="group.id"
        class="group-item"
        :data-index="startIndex + index"
      >
        <div class="group-header">
          <h3 class="group-title">组 {{ startIndex + index + 1 }}</h3>
          <div class="group-info">
            <span class="file-count">{{ group.files.length }} 个文件</span>
            <span class="group-size">{{ formatFileSize(group.totalSize) }}</span>
            <button 
              @click="toggleGroupExpansion(group.id)"
              class="expand-btn"
            >
              {{ group.isExpanded ? '折叠' : '展开' }}
            </button>
          </div>
        </div>
        
        <!-- 缩略图网格 -->
        <div v-if="group.isExpanded" class="thumbnail-grid">
          <div 
            v-for="(file, fileIndex) in group.files" 
            :key="file.path"
            class="thumbnail-item"
            :class="{ selected: file.selected }"
            @click="toggleFileSelection(startIndex + index, fileIndex)"
          >
            <!-- 缩略图图片 -->
            <div class="thumbnail-wrapper">
              <img 
                v-if="file.thumbnailData"
                :src="`data:image/webp;base64,${file.thumbnailData}`"
                :alt="file.name"
                class="thumbnail-image"
                @error="handleThumbnailError(file)"
              />
              <div v-else-if="file.thumbnailLoading" class="thumbnail-loading">
                <div class="loading-spinner"></div>
              </div>
              <div v-else class="thumbnail-placeholder">
                <svg class="file-icon" viewBox="0 0 24 24">
                  <path d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"/>
                </svg>
              </div>
              
              <!-- 选择复选框 -->
              <div class="selection-overlay" v-if="file.selected">
                <svg class="check-icon" viewBox="0 0 24 24">
                  <path d="M5 13l4 4L19 7"/>
                </svg>
              </div>
            </div>
            
            <!-- 文件信息 -->
            <div class="file-info">
              <div class="file-name" :title="file.name">{{ file.name }}</div>
              <div class="file-size">{{ formatFileSize(file.size) }}</div>
            </div>
          </div>
        </div>
        
        <!-- 折叠状态下的预览 -->
        <div v-else class="collapsed-preview">
          <div 
            v-for="(file, fileIndex) in group.files.slice(0, 4)" 
            :key="file.path"
            class="mini-thumbnail"
          >
            <img 
              v-if="file.thumbnailData"
              :src="`data:image/webp;base64,${file.thumbnailData}`"
              :alt="file.name"
              class="mini-thumbnail-image"
            />
            <div v-else class="mini-thumbnail-placeholder"></div>
          </div>
          <div v-if="group.files.length > 4" class="more-indicator">
            +{{ group.files.length - 4 }}
          </div>
        </div>
      </div>
      
      <!-- 底部占位符 -->
      <div :style="{ height: bottomSpacerHeight + 'px' }"></div>
    </div>
    
    <!-- 加载更多指示器 -->
    <div v-if="isLoadingThumbnails" class="loading-indicator">
      <div class="loading-spinner"></div>
      <span>正在生成缩略图...</span>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, onMounted, onUnmounted, nextTick, watch } from 'vue'
import { invoke } from '@tauri-apps/api/tauri'

interface FileInfo {
  name: string
  path: string
  size: number
  modified: Date
  selected: boolean
  thumbnailData?: string
  thumbnailLoading?: boolean
  thumbnailError?: boolean
}

interface DuplicateGroup {
  id: string
  files: FileInfo[]
  totalSize: number
  isExpanded: boolean
}

interface Props {
  groups: DuplicateGroup[]
  itemHeight?: number
  containerHeight?: number
}

const props = withDefaults(defineProps<Props>(), {
  itemHeight: 300,
  containerHeight: 600
})

const emit = defineEmits<{
  'update:groups': [groups: DuplicateGroup[]]
  'file-select': [groupIndex: number, fileIndex: number, selected: boolean]
}>()

// 虚拟列表状态
const containerRef = ref<HTMLElement>()
const scrollTop = ref(0)
const visibleCount = ref(10)
const startIndex = ref(0)
const isLoadingThumbnails = ref(false)

// IntersectionObserver 用于懒加载
let thumbnailObserver: IntersectionObserver | null = null
const observedElements = new Set<string>()

// 计算属性
const visibleGroups = computed(() => {
  const start = startIndex.value
  const end = Math.min(start + visibleCount.value, props.groups.length)
  return props.groups.slice(start, end)
})

const topSpacerHeight = computed(() => {
  return startIndex.value * props.itemHeight
})

const bottomSpacerHeight = computed(() => {
  const remaining = props.groups.length - (startIndex.value + visibleCount.value)
  return Math.max(0, remaining) * props.itemHeight
})

// 滚动处理
const handleScroll = (event: Event) => {
  const target = event.target as HTMLElement
  scrollTop.value = target.scrollTop
  
  const newStartIndex = Math.floor(scrollTop.value / props.itemHeight)
  const newVisibleCount = Math.ceil(props.containerHeight / props.itemHeight) + 5 // 缓冲区
  
  if (newStartIndex !== startIndex.value) {
    startIndex.value = newStartIndex
  }
  
  if (newVisibleCount !== visibleCount.value) {
    visibleCount.value = newVisibleCount
  }
  
  // 触发缩略图懒加载
  nextTick(() => {
    observeVisibleThumbnails()
  })
}

// 设置 IntersectionObserver
const setupThumbnailObserver = () => {
  thumbnailObserver = new IntersectionObserver(
    (entries) => {
      entries.forEach((entry) => {
        if (entry.isIntersecting) {
          const filePath = entry.target.getAttribute('data-file-path')
          if (filePath) {
            loadThumbnail(filePath)
          }
        }
      })
    },
    {
      root: containerRef.value,
      rootMargin: '100px',
      threshold: 0.1
    }
  )
}

// 观察可见的缩略图
const observeVisibleThumbnails = () => {
  if (!thumbnailObserver) return
  
  const thumbnailElements = containerRef.value?.querySelectorAll('.thumbnail-item')
  
  thumbnailElements?.forEach((element) => {
    const filePath = element.querySelector('.thumbnail-wrapper')?.getAttribute('data-file-path')
    if (filePath && !observedElements.has(filePath)) {
      thumbnailObserver?.observe(element)
      observedElements.add(filePath)
    }
  })
}

// 加载缩略图
const loadThumbnail = async (filePath: string) => {
  // 查找对应的文件对象
  let targetFile: FileInfo | null = null
  let groupIndex = -1
  let fileIndex = -1
  
  for (let i = 0; i < props.groups.length; i++) {
    const fileIdx = props.groups[i].files.findIndex(f => f.path === filePath)
    if (fileIdx !== -1) {
      targetFile = props.groups[i].files[fileIdx]
      groupIndex = i
      fileIndex = fileIdx
      break
    }
  }
  
  if (!targetFile || targetFile.thumbnailData || targetFile.thumbnailLoading) {
    return
  }
  
  // 设置加载状态
  targetFile.thumbnailLoading = true
  
  try {
    const thumbnailInfo = await invoke<{
      data: string
      width: number
      height: number
      size: number
    }>('generate_thumbnail', { filePath })
    
    // 更新缩略图数据
    targetFile.thumbnailData = thumbnailInfo.data
    targetFile.thumbnailLoading = false
    
    console.log(`缩略图生成成功: ${filePath}, 大小: ${thumbnailInfo.size} 字节`)
    
  } catch (error) {
    console.error(`缩略图生成失败: ${filePath}`, error)
    targetFile.thumbnailError = true
    targetFile.thumbnailLoading = false
  }
}

// 批量预加载缩略图
const preloadThumbnails = async () => {
  isLoadingThumbnails.value = true
  
  try {
    // 只为可见区域和即将可见的区域预加载缩略图
    const preloadGroups = props.groups.slice(
      Math.max(0, startIndex.value - 2),
      Math.min(props.groups.length, startIndex.value + visibleCount.value + 2)
    )
    
    const loadPromises: Promise<void>[] = []
    
    preloadGroups.forEach(group => {
      if (group.isExpanded) {
        group.files.forEach(file => {
          if (!file.thumbnailData && !file.thumbnailLoading && !file.thumbnailError) {
            loadPromises.push(loadThumbnail(file.path))
          }
        })
      } else {
        // 为折叠状态加载前4个文件的缩略图
        group.files.slice(0, 4).forEach(file => {
          if (!file.thumbnailData && !file.thumbnailLoading && !file.thumbnailError) {
            loadPromises.push(loadThumbnail(file.path))
          }
        })
      }
    })
    
    // 限制并发数量
    const batchSize = 5
    for (let i = 0; i < loadPromises.length; i += batchSize) {
      const batch = loadPromises.slice(i, i + batchSize)
      await Promise.allSettled(batch)
    }
    
  } finally {
    isLoadingThumbnails.value = false
  }
}

// 工具函数
const formatFileSize = (bytes: number): string => {
  if (bytes === 0) return '0 B'
  const k = 1024
  const sizes = ['B', 'KB', 'MB', 'GB', 'TB']
  const i = Math.floor(Math.log(bytes) / Math.log(k))
  return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
}

const toggleGroupExpansion = (groupId: string) => {
  const group = props.groups.find(g => g.id === groupId)
  if (group) {
    group.isExpanded = !group.isExpanded
    
    // 如果展开了组，预加载该组的缩略图
    if (group.isExpanded) {
      nextTick(() => {
        preloadThumbnails()
      })
    }
  }
}

const toggleFileSelection = (groupIndex: number, fileIndex: number) => {
  const file = props.groups[groupIndex].files[fileIndex]
  file.selected = !file.selected
  emit('file-select', groupIndex, fileIndex, file.selected)
}

const handleThumbnailError = (file: FileInfo) => {
  file.thumbnailError = true
  file.thumbnailLoading = false
}

// 生命周期
onMounted(() => {
  setupThumbnailObserver()
  
  nextTick(() => {
    observeVisibleThumbnails()
    preloadThumbnails()
  })
})

onUnmounted(() => {
  if (thumbnailObserver) {
    thumbnailObserver.disconnect()
  }
})

// 监听组数据变化
watch(() => props.groups, () => {
  nextTick(() => {
    observeVisibleThumbnails()
    preloadThumbnails()
  })
}, { deep: true })
</script>

<style scoped>
.thumbnail-grid-container {
  width: 100%;
  height: 100%;
  position: relative;
}

.virtual-list {
  overflow-y: auto;
  width: 100%;
}

.group-item {
  margin-bottom: 24px;
  background: white;
  border-radius: 8px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  overflow: hidden;
}

.group-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 16px 20px;
  background: #f8f9fa;
  border-bottom: 1px solid #e9ecef;
}

.group-title {
  margin: 0;
  font-size: 18px;
  font-weight: 600;
  color: #333;
}

.group-info {
  display: flex;
  align-items: center;
  gap: 12px;
}

.file-count, .group-size {
  font-size: 14px;
  color: #666;
  padding: 4px 8px;
  background: white;
  border-radius: 4px;
}

.expand-btn {
  padding: 6px 12px;
  background: #007bff;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 14px;
  transition: background-color 0.2s;
}

.expand-btn:hover {
  background: #0056b3;
}

.thumbnail-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 16px;
  padding: 20px;
}

.thumbnail-item {
  position: relative;
  cursor: pointer;
  border-radius: 8px;
  overflow: hidden;
  transition: transform 0.2s, box-shadow 0.2s;
  border: 2px solid transparent;
}

.thumbnail-item:hover {
  transform: translateY(-2px);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}

.thumbnail-item.selected {
  border-color: #007bff;
  box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25);
}

.thumbnail-wrapper {
  position: relative;
  width: 100%;
  height: 200px;
  background: #f8f9fa;
  display: flex;
  align-items: center;
  justify-content: center;
}

.thumbnail-image {
  max-width: 100%;
  max-height: 100%;
  object-fit: cover;
  border-radius: 4px;
}

.thumbnail-loading, .thumbnail-placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  color: #666;
}

.loading-spinner {
  width: 24px;
  height: 24px;
  border: 2px solid #f3f3f3;
  border-top: 2px solid #007bff;
  border-radius: 50%;
  animation: spin 1s linear infinite;
}

.file-icon {
  width: 48px;
  height: 48px;
  stroke: currentColor;
  fill: none;
  stroke-width: 2;
}

.selection-overlay {
  position: absolute;
  top: 8px;
  right: 8px;
  width: 24px;
  height: 24px;
  background: #007bff;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.check-icon {
  width: 16px;
  height: 16px;
  stroke: white;
  fill: none;
  stroke-width: 2;
}

.file-info {
  padding: 12px;
  background: white;
}

.file-name {
  font-size: 14px;
  font-weight: 500;
  color: #333;
  margin-bottom: 4px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.file-size {
  font-size: 12px;
  color: #666;
}

.collapsed-preview {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 16px 20px;
}

.mini-thumbnail {
  width: 60px;
  height: 60px;
  border-radius: 4px;
  overflow: hidden;
  background: #f8f9fa;
  display: flex;
  align-items: center;
  justify-content: center;
}

.mini-thumbnail-image {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.mini-thumbnail-placeholder {
  width: 100%;
  height: 100%;
  background: #e9ecef;
}

.more-indicator {
  font-size: 14px;
  color: #666;
  font-weight: 500;
}

.loading-indicator {
  position: absolute;
  bottom: 20px;
  right: 20px;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 12px 16px;
  background: rgba(0, 0, 0, 0.8);
  color: white;
  border-radius: 20px;
  font-size: 14px;
}

@keyframes spin {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}

/* 滚动条样式 */
.virtual-list::-webkit-scrollbar {
  width: 8px;
}

.virtual-list::-webkit-scrollbar-track {
  background: #f1f1f1;
  border-radius: 4px;
}

.virtual-list::-webkit-scrollbar-thumb {
  background: #c1c1c1;
  border-radius: 4px;
}

.virtual-list::-webkit-scrollbar-thumb:hover {
  background: #a8a8a8;
}
</style>
